package com.ssy.lingxi.member.merchant.serviceimpl.base;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.api.model.constant.MemberProcessTypeEnum;
import com.ssy.lingxi.member.merchant.entity.*;
import com.ssy.lingxi.member.merchant.model.bo.*;
import com.ssy.lingxi.member.merchant.model.constant.*;
import com.ssy.lingxi.member.merchant.model.vo.basic.response.*;
import com.ssy.lingxi.member.merchant.repository.MemberDepositoryDetailHistoryRepository;
import com.ssy.lingxi.member.merchant.repository.MemberDepositoryDetailRepository;
import com.ssy.lingxi.member.merchant.repository.MemberProcessRuleRepository;
import com.ssy.lingxi.member.merchant.repository.MemberRelationRepository;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberDepositDetailService;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberHistoryService;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberRegisterDetailService;
import com.ssy.lingxi.member.merchant.service.feign.IMessageFeignService;
import com.ssy.lingxi.member.merchant.service.feign.IReportFeignService;
import com.ssy.lingxi.member.merchant.service.feign.IWorkflowFeignService;
import com.ssy.lingxi.member.merchant.service.web.IMemberProcessRuleService;
import com.ssy.lingxi.member.merchant.utils.NumberUtil;
import com.ssy.lingxi.member.merchant.utils.SecurityStringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 会员入库资料基础服务接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-05-20
 */
@Service
public class BaseMemberDepositDetailServiceImpl implements IBaseMemberDepositDetailService {
    @Resource
    private MemberProcessRuleRepository memberProcessRuleRepository;

    @Resource
    private IBaseMemberRegisterDetailService baseMemberRegisterDetailService;

    @Resource
    private IBaseMemberHistoryService baseMemberHistoryService;

    @Resource
    private MemberDepositoryDetailRepository memberDepositoryDetailRepository;

    @Resource
    private MemberDepositoryDetailHistoryRepository memberDepositoryDetailHistoryRepository;

    @Resource
    private IMemberProcessRuleService memberProcessRuleService;

    @Resource
    private IWorkflowFeignService workflowFeignService;

    @Resource
    private MemberRelationRepository relationRepository;

    @Resource
    private IMessageFeignService messageFeignService;

    @Resource
    private IReportFeignService reportFeignService;

    /**
     * 查询会员入库资料配置列表
     *
     * @param memberId 会员Id
     * @param roleId   角色Id
     * @param subRole  下级会员角色
     * @return 查询结果
     */
    @Override
    public List<MemberConfigDO> findMemberDepositoryConfig(Long memberId, Long roleId, RoleDO subRole) {
        MemberProcessRuleDO processRule = memberProcessRuleRepository.findFirstByMemberIdAndRoleIdAndSubRoleAndStatus(memberId, roleId, subRole, EnableDisableStatus.ENABLE.getCode());
        return processRule == null || CollectionUtils.isEmpty(processRule.getConfigs()) ? new ArrayList<>() : new ArrayList<>(processRule.getConfigs());
    }

    /**
     * 将注册资料转换为分组内容
     *
     * @param memberConfigs 注册资料列表
     * @return 分组内容
     */
    @Override
    public List<RegisterDetailGroupVO> groupMemberConfig(List<MemberConfigDO> memberConfigs) {
        if(CollectionUtils.isEmpty(memberConfigs)) {
            return new ArrayList<>();
        }

        Map<String, List<MemberConfigDO>> groupList = memberConfigs.stream().filter(c -> c.getFieldStatus().equals(MemberConfigStatusEnum.ENABLED.getCode()))
                .collect(Collectors.groupingBy(MemberConfigDO::getGroupName));

        return groupList.entrySet().stream().map(e -> {
            RegisterDetailGroupVO detailGroup = new RegisterDetailGroupVO();
            detailGroup.setGroupName(e.getKey());

            List<RegisterDetailVO> elements = e.getValue().stream().map(c -> {
                RegisterDetailVO detail = new RegisterDetailVO();
                detail.setFieldName(c.getFieldName());
                detail.setFieldLocalName(c.getFieldLocalName());
                detail.setFieldType(c.getFieldType());
                detail.setAttr(c.getAttr());
                detail.setFieldEmpty(c.getFieldEmpty());
                detail.setFieldLength(c.getFieldLength());
                detail.setFieldOrder(c.getFieldOrder());
                detail.setFieldRemark(c.getFieldRemark());
                detail.setRuleEnum(c.getRuleEnum());
                detail.setPattern(c.getRuleEnum().equals(0) ? "" : MemberConfigCheckRuleEnum.getJsPattern(c.getRuleEnum()));
                detail.setMsg(c.getRuleEnum().equals(0) ? "" : MemberConfigCheckRuleEnum.getMsg(c.getRuleEnum()));
                detail.setFieldEnum(CollectionUtils.isEmpty(c.getLabels()) ? new ArrayList<>() : c.getLabels().stream().sorted(Comparator.comparingInt(MemberConfigLabelDO::getLabelOrder)).map(label -> new ConfigDetailLabelVO(label.getId(), label.getLabelValue())).collect(Collectors.toList()));

                DetailValueBO valueBO = getDetailValue(c);
                detail.setFieldValue(valueBO.getFieldValue());
                detail.setLastValue(valueBO.getLastValue());

                return detail;
            }).sorted(Comparator.comparingInt(RegisterDetailVO::getFieldOrder)).collect(Collectors.toList());

            detailGroup.setElements(elements);
            return detailGroup;
        }).sorted(Comparator.comparingInt(a -> a.getElements().get(0).getFieldOrder())).collect(Collectors.toList());
    }

    /**
     * 入库审核过程中，新增或修改入库资料时，分组展示“待审核”的入库资料
     *
     * @param relationDO 会员关系
     * @return 分组内容
     */
    @Override
    public List<RegisterDetailGroupVO> groupMemberDepositoryDetail(MemberRelationDO relationDO) {
        List<MemberDepositoryDetailDO> depositoryDetails = memberDepositoryDetailRepository.findByRelationAndVersion(relationDO, MemberDetailVersionEnum.TO_BE_VALIDATE.getCode());

        if(!CollectionUtils.isEmpty(depositoryDetails)) {
            Map<String, List<MemberDepositoryDetailDO>> groupList = depositoryDetails.stream().filter(c -> c.getStatus().equals(MemberConfigStatusEnum.ENABLED.getCode()))
                    .collect(Collectors.groupingBy(MemberDepositoryDetailDO::getGroupName));

            return groupList.entrySet().stream().map(e -> {
                RegisterDetailGroupVO detailGroup = new RegisterDetailGroupVO();
                detailGroup.setGroupName(e.getKey());

                List<RegisterDetailVO> elements = e.getValue().stream().map(c -> {
                    RegisterDetailVO detail = new RegisterDetailVO();
                    detail.setFieldName(c.getFieldName());
                    detail.setFieldLocalName(c.getFieldLocalName());
                    detail.setFieldType(c.getFieldType());
                    detail.setAttr(c.getAttr());
                    detail.setFieldEmpty(c.getMemberConfig().getFieldEmpty());
                    detail.setFieldLength(c.getMemberConfig().getFieldLength());
                    detail.setFieldOrder(c.getMemberConfig().getFieldOrder());
                    detail.setFieldRemark(c.getMemberConfig().getFieldRemark());
                    detail.setRuleEnum(c.getMemberConfig().getRuleEnum());
                    detail.setPattern(c.getMemberConfig().getRuleEnum().equals(0) ? "" : MemberConfigCheckRuleEnum.getJsPattern(c.getMemberConfig().getRuleEnum()));
                    detail.setMsg(c.getMemberConfig().getRuleEnum().equals(0) ? "" : MemberConfigCheckRuleEnum.getMsg(c.getMemberConfig().getRuleEnum()));
                    detail.setFieldEnum(CollectionUtils.isEmpty(c.getMemberConfig().getLabels()) ? new ArrayList<>() : c.getMemberConfig().getLabels().stream().sorted(Comparator.comparingInt(MemberConfigLabelDO::getLabelOrder)).map(label -> new ConfigDetailLabelVO(label.getId(), label.getLabelValue())).collect(Collectors.toList()));

                    DetailValueBO valueBO = getDetailValue(c);
                    detail.setFieldValue(valueBO.getFieldValue());
                    detail.setLastValue(valueBO.getLastValue());

                    return detail;
                }).sorted(Comparator.comparingInt(RegisterDetailVO::getFieldOrder)).collect(Collectors.toList());

                detailGroup.setElements(elements);
                return detailGroup;
            }).sorted(Comparator.comparingInt(a -> a.getElements().get(0).getFieldOrder())).collect(Collectors.toList());
        }

        return groupMemberConfig(findMemberDepositoryConfig(relationDO.getMemberId(), relationDO.getRoleId(), relationDO.getSubRole()));
    }

    /**
     * 更新入库资料，保存入库，判断是否启动会员变更流程
     *
     * @param relationDO 会员关系
     * @param detailMap  修改后的入库资料
     * @return 是否需要重新入库审核
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> checkAndUpdateMemberDepositoryDetail(MemberRelationDO relationDO, Map<String, Object> detailMap) {
        switch (MemberOuterStatusEnum.parseCode(relationDO.getOuterStatus())) {
            //入库审核、变更审核通过后，比对正在使用的版本，启动变更流程
            case DEPOSITORY_PASSED:
            case MODIFY_PASSED:
                return updateValidatePassedDetails(relationDO, detailMap);
            //入库审核不通过，比对正在使用的版本，强制重启入库流程
            case DEPOSITORY_NOT_PASSED:
                return updateDepositNotPassedDetails(relationDO, detailMap);
            //变更审核不通过，比对审核中的版本，强制重启变更流程
            case MODIFY_NOT_PASSED:
                return updateModifyNotPassedDetails(relationDO, detailMap);
            default:
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_VERIFYING);
        }
    }

    /**
     * 入库审核、变更审核通过后，修改入库资料，比对“正在使用”的版本，判断是否需要启动变更流程
     * @param relationDO 会员关系
     * @param detailMap 入库资料
     * @return 操作结果
     */
    private Wrapper<Void> updateValidatePassedDetails(MemberRelationDO relationDO, Map<String, Object> detailMap) {
        List<MemberDepositoryDetailDO> existList = memberDepositoryDetailRepository.findByRelation(relationDO);
        if(CollectionUtils.isEmpty(existList)) {
            return Wrapper.success();
        }
        //记录执行之前的内部状态
        int lastInnerStatus = relationDO.getInnerStatus();
        //入库审核、变更审核通过后，入库资料只会存在“正在使用”的版本
        List<MemberDepositoryDetailDO> usingList = existList.stream().filter(detail -> detail.getVersion().equals(MemberDetailVersionEnum.USING.getCode())).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(usingList)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DEPOSITORY_DETAIL_NOT_EXIST);
        }

        //判断入库资料字段是否齐全
        Wrapper<Void> checkFieldResult = checkDetailFields(usingList, detailMap);
        if(checkFieldResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(checkFieldResult.getCode(), checkFieldResult.getMessage());
        }

        List<MemberDepositoryDetailDO> depositoryDetails = new ArrayList<>();
        //资料是否变更
        boolean detailChanged = false;
        //判断是否需要重新审核
        boolean needValidate = false;
        for (Map.Entry<String, Object> entry : detailMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue() instanceof HashMap ? SecurityStringUtils.serializeObject(entry.getValue()) : String.valueOf(entry.getValue());

            MemberDepositoryDetailDO usingDetailDO = usingList.stream().filter(c -> c.getFieldName().equals(key)).findFirst().orElse(null);
            if (usingDetailDO == null) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DEPOSITORY_DETAIL_NOT_EXIST);
            }

            MemberConfigDO configDO = usingDetailDO.getMemberConfig();
            if(configDO == null) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_CONFIG_DOES_NOT_EXIST);
            }

            Wrapper<DetailCheckBO> checkResult = baseMemberRegisterDetailService.checkDetail(configDO, value);
            if(checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(checkResult.getCode(), checkResult.getMessage());
            }

            //判断是否需要重新审核
            if(!usingDetailDO.getDetail().equals(checkResult.getData().getDetail())) {
                detailChanged = true;
                needValidate = needValidate || NumberUtil.notNullOrZero(configDO.getValidate());
            }

            MemberDepositoryDetailDO memberDepositoryDetailDO = new MemberDepositoryDetailDO();
            memberDepositoryDetailDO.setCreateTime(LocalDateTime.now());
            memberDepositoryDetailDO.setMemberConfig(configDO);
            memberDepositoryDetailDO.setGroupName(configDO.getGroupName());
            memberDepositoryDetailDO.setRelation(relationDO);
            memberDepositoryDetailDO.setFieldName(configDO.getFieldName());
            memberDepositoryDetailDO.setFieldLocalName(configDO.getFieldLocalName());
            memberDepositoryDetailDO.setFieldType(configDO.getFieldType());
            memberDepositoryDetailDO.setAttr(configDO.getAttr());
            memberDepositoryDetailDO.setTagEnum(configDO.getTagEnum());
            memberDepositoryDetailDO.setStatus(configDO.getFieldStatus());
            memberDepositoryDetailDO.setValidate(configDO.getValidate());
            memberDepositoryDetailDO.setDetail(checkResult.getData().getDetail());
            memberDepositoryDetailDO.setProvinceCode(checkResult.getData().getProvinceCode());
            memberDepositoryDetailDO.setProvinceName(checkResult.getData().getProvinceName());
            memberDepositoryDetailDO.setCityCode(checkResult.getData().getCityCode());
            memberDepositoryDetailDO.setCityName(checkResult.getData().getCityName());
            memberDepositoryDetailDO.setDistrictCode(checkResult.getData().getDistrictCode());
            memberDepositoryDetailDO.setDistrictName(checkResult.getData().getDistrictName());
            memberDepositoryDetailDO.setLabels(checkResult.getData().getLabels());
            depositoryDetails.add(memberDepositoryDetailDO);
        }

        //资料没有发生变更，返回
        if(!detailChanged) {
            return Wrapper.success();
        }

        //如果需要重新审核，新的资料为“正在审核版本”，启动变更流程
        //如果不需要重新审核，新的资料为“正在使用”的版本，直接更改
        //查询变更流程
        ProcessBO modifyProcess = memberProcessRuleService.findMemberProcessKey(relationDO, MemberProcessTypeEnum.MEMBER_MODIFICATION);
        if(needValidate && !modifyProcess.getEmptyProcess()) {
            Wrapper<WorkflowTaskResultBO> taskResult = workflowFeignService.startMemberProcess(modifyProcess.getProcessKey(), relationDO.getMemberId(), relationDO.getRoleId(), relationDO.getId());
            if (taskResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
            }

            relationDO.setInnerStatus(taskResult.getData().getInnerStatus());
            relationDO.setOuterStatus(MemberOuterStatusEnum.MODIFYING.getCode());
            relationDO.getValidateTask().setTaskId(taskResult.getData().getTaskId());
            relationDO.getValidateTask().setProcessKey(modifyProcess.getProcessKey());
            relationDO.getValidateTask().setProcessTypeEnum(MemberProcessTypeEnum.MEMBER_MODIFICATION.getCode());

            //如果之前有“审核中”的版本，删除
            List<MemberDepositoryDetailDO> deleteList = existList.stream().filter(detail -> detail.getVersion().equals(MemberDetailVersionEnum.TO_BE_VALIDATE.getCode())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(deleteList)) {
                relationDO.getDepositDetails().removeIf(detail -> detail.getVersion().equals(MemberDetailVersionEnum.TO_BE_VALIDATE.getCode()));
                memberDepositoryDetailRepository.deleteAll(deleteList);
            }

            //保存修改后的入库资料
            depositoryDetails.forEach(detail -> detail.setVersion(MemberDetailVersionEnum.TO_BE_VALIDATE.getCode()));
            memberDepositoryDetailRepository.saveAll(depositoryDetails);
            //添加
            relationDO.getDepositDetails().addAll(depositoryDetails);

            //更新统计数
            reportFeignService.reportMemberValidate(relationDO.getId(), relationDO.getMemberId(), relationDO.getRoleId(), lastInnerStatus, taskResult.getData().getInnerStatus(), relationDO.getValidateTask().getProcessTypeEnum());
            //发送消息
            messageFeignService.sendMemberValidateMessage(relationDO);
            //记录外部记录
            baseMemberHistoryService.saveMemberOuterHistory(relationDO, relationDO.getSubRoleName(), MemberValidateHistoryOperationEnum.MODIFY_DEPOSIT_DETAIL, MemberOuterStatusEnum.getCodeMsg(relationDO.getOuterStatus()), "");
        } else {
            relationDO.getDepositDetails().clear();
            //删除之前所有的
            memberDepositoryDetailRepository.deleteByRelation(relationDO);

            depositoryDetails.forEach(detail -> detail.setVersion(MemberDetailVersionEnum.USING.getCode()));
            memberDepositoryDetailRepository.saveAll(depositoryDetails);

            relationDO.setDepositDetails(new HashSet<>(depositoryDetails));
        }

        relationRepository.saveAndFlush(relationDO);

        return Wrapper.success();
    }

    /**
     * 入库审核不通过，修改入库资料，比对“审核中”的版本，强制重启入库流程
     * @param relationDO 会员关系
     * @param detailMap 入库资料
     * @return 操作结果
     */
    private Wrapper<Void> updateDepositNotPassedDetails(MemberRelationDO relationDO, Map<String, Object> detailMap) {
        //入库审核不通过后，入库资料必须存在“审核中”的版本，不存在“正在使用”的版本
        //即使没有入库资料，也要强制重启流程
        List<MemberDepositoryDetailDO> usingList = memberDepositoryDetailRepository.findByRelationAndVersion(relationDO, MemberDetailVersionEnum.TO_BE_VALIDATE.getCode());

        //判断入库资料字段是否齐全
        Wrapper<Void> checkFieldResult = checkDetailFields(usingList, detailMap);
        if(checkFieldResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(checkFieldResult.getCode(), checkFieldResult.getMessage());
        }

        List<MemberDepositoryDetailDO> depositoryDetails = new ArrayList<>();
        for (Map.Entry<String, Object> entry : detailMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue() instanceof HashMap ? SecurityStringUtils.serializeObject(entry.getValue()) : String.valueOf(entry.getValue());

            MemberDepositoryDetailDO usingDetailDO = usingList.stream().filter(c -> c.getFieldName().equals(key)).findFirst().orElse(null);
            if (usingDetailDO == null) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DEPOSITORY_DETAIL_NOT_EXIST);
            }

            MemberConfigDO configDO = usingDetailDO.getMemberConfig();
            if(configDO == null) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_CONFIG_DOES_NOT_EXIST);
            }

            Wrapper<DetailCheckBO> checkResult = baseMemberRegisterDetailService.checkDetail(configDO, value);
            if(checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(checkResult.getCode(), checkResult.getMessage());
            }

            MemberDepositoryDetailDO memberDepositoryDetailDO = new MemberDepositoryDetailDO();
            memberDepositoryDetailDO.setCreateTime(LocalDateTime.now());
            memberDepositoryDetailDO.setMemberConfig(configDO);
            memberDepositoryDetailDO.setGroupName(configDO.getGroupName());
            memberDepositoryDetailDO.setRelation(relationDO);
            memberDepositoryDetailDO.setFieldName(configDO.getFieldName());
            memberDepositoryDetailDO.setFieldLocalName(configDO.getFieldLocalName());
            memberDepositoryDetailDO.setFieldType(configDO.getFieldType());
            memberDepositoryDetailDO.setAttr(configDO.getAttr());
            memberDepositoryDetailDO.setTagEnum(configDO.getTagEnum());
            memberDepositoryDetailDO.setStatus(configDO.getFieldStatus());
            memberDepositoryDetailDO.setValidate(configDO.getValidate());
            memberDepositoryDetailDO.setDetail(checkResult.getData().getDetail());
            memberDepositoryDetailDO.setProvinceCode(checkResult.getData().getProvinceCode());
            memberDepositoryDetailDO.setProvinceName(checkResult.getData().getProvinceName());
            memberDepositoryDetailDO.setCityCode(checkResult.getData().getCityCode());
            memberDepositoryDetailDO.setCityName(checkResult.getData().getCityName());
            memberDepositoryDetailDO.setDistrictCode(checkResult.getData().getDistrictCode());
            memberDepositoryDetailDO.setDistrictName(checkResult.getData().getDistrictName());
            memberDepositoryDetailDO.setLabels(checkResult.getData().getLabels());
            //版本
            memberDepositoryDetailDO.setVersion(MemberDetailVersionEnum.TO_BE_VALIDATE.getCode());
            depositoryDetails.add(memberDepositoryDetailDO);
        }

        //强制重启入库流程
        ProcessBO depositProcess = memberProcessRuleService.findMemberProcessKey(relationDO, MemberProcessTypeEnum.MEMBER_DEPOSITORY);
        if(depositProcess.getEmptyProcess()) {
            //删除之前所有版本，将修改后的版本设置为“正在使用的版本”
            relationDO.getDepositDetails().clear();
            memberDepositoryDetailRepository.deleteByRelation(relationDO);
            depositoryDetails.forEach(detail -> detail.setVersion(MemberDetailVersionEnum.USING.getCode()));
        } else {
            if (!StringUtils.hasLength(relationDO.getValidateTask().getProcessKey()) || !relationDO.getValidateTask().getProcessTypeEnum().equals(MemberProcessTypeEnum.MEMBER_DEPOSITORY.getCode())) {
                relationDO.getValidateTask().setProcessTypeEnum(MemberProcessTypeEnum.MEMBER_DEPOSITORY.getCode());
                relationDO.getValidateTask().setProcessKey(depositProcess.getProcessKey());
            }

            Wrapper<WorkflowTaskResultBO> taskResult = workflowFeignService.startMemberProcess(relationDO.getValidateTask().getProcessKey(), relationDO.getMemberId(), relationDO.getRoleId(), relationDO.getId());
            if (taskResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
            }

            relationDO.setInnerStatus(taskResult.getData().getInnerStatus());
            relationDO.setOuterStatus(MemberOuterStatusEnum.DEPOSITING.getCode());
            relationDO.getValidateTask().setTaskId(taskResult.getData().getTaskId());

            //如果之前有“审核中”的版本，删除
            relationDO.getDepositDetails().removeIf(detail -> detail.getVersion().equals(MemberDetailVersionEnum.TO_BE_VALIDATE.getCode()));
            memberDepositoryDetailRepository.deleteByRelationAndVersion(relationDO, MemberDetailVersionEnum.TO_BE_VALIDATE.getCode());
        }


        memberDepositoryDetailRepository.saveAll(depositoryDetails);
        relationDO.getDepositDetails().addAll(depositoryDetails);

        relationRepository.saveAndFlush(relationDO);

        //外部记录
        baseMemberHistoryService.saveMemberOuterHistory(relationDO, relationDO.getSubRoleName(), MemberValidateHistoryOperationEnum.APPLY_FOR_SUB_MEMBER, MemberOuterStatusEnum.getCodeMsg(relationDO.getOuterStatus()), "");

        return Wrapper.success();
    }

    /**
     * 变更审核不通过，修改入库资料，比对“审核中”的版本，强制重启变更流程
     * @param relationDO 会员关系
     * @param detailMap 入库资料
     * @return 操作结果
     */
    private Wrapper<Void> updateModifyNotPassedDetails(MemberRelationDO relationDO, Map<String, Object> detailMap) {
        //变更审核不通过后，入库资料必须存在“审核中”的版本，必须存在“正在使用”的版本
        List<MemberDepositoryDetailDO> usingList = memberDepositoryDetailRepository.findByRelationAndVersion(relationDO, MemberDetailVersionEnum.TO_BE_VALIDATE.getCode());
        if(CollectionUtils.isEmpty(usingList)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DEPOSITORY_DETAIL_NOT_EXIST);
        }

        //判断入库资料字段是否齐全
        Wrapper<Void> checkFieldResult = checkDetailFields(usingList, detailMap);
        if(checkFieldResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(checkFieldResult.getCode(), checkFieldResult.getMessage());
        }

        List<MemberDepositoryDetailDO> depositoryDetails = new ArrayList<>();
        for (Map.Entry<String, Object> entry : detailMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue() instanceof HashMap ? SecurityStringUtils.serializeObject(entry.getValue()) : String.valueOf(entry.getValue());

            MemberDepositoryDetailDO usingDetailDO = usingList.stream().filter(c -> c.getFieldName().equals(key)).findFirst().orElse(null);
            if (usingDetailDO == null) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DEPOSITORY_DETAIL_NOT_EXIST);
            }

            MemberConfigDO configDO = usingDetailDO.getMemberConfig();
            if(configDO == null) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_CONFIG_DOES_NOT_EXIST);
            }

            Wrapper<DetailCheckBO> checkResult = baseMemberRegisterDetailService.checkDetail(configDO, value);
            if(checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(checkResult.getCode(), checkResult.getMessage());
            }

            MemberDepositoryDetailDO memberDepositoryDetailDO = new MemberDepositoryDetailDO();
            memberDepositoryDetailDO.setCreateTime(LocalDateTime.now());
            memberDepositoryDetailDO.setMemberConfig(configDO);
            memberDepositoryDetailDO.setGroupName(configDO.getGroupName());
            memberDepositoryDetailDO.setRelation(relationDO);
            memberDepositoryDetailDO.setFieldName(configDO.getFieldName());
            memberDepositoryDetailDO.setFieldLocalName(configDO.getFieldLocalName());
            memberDepositoryDetailDO.setFieldType(configDO.getFieldType());
            memberDepositoryDetailDO.setAttr(configDO.getAttr());
            memberDepositoryDetailDO.setTagEnum(configDO.getTagEnum());
            memberDepositoryDetailDO.setStatus(configDO.getFieldStatus());
            memberDepositoryDetailDO.setValidate(configDO.getValidate());
            memberDepositoryDetailDO.setDetail(checkResult.getData().getDetail());
            memberDepositoryDetailDO.setProvinceCode(checkResult.getData().getProvinceCode());
            memberDepositoryDetailDO.setProvinceName(checkResult.getData().getProvinceName());
            memberDepositoryDetailDO.setCityCode(checkResult.getData().getCityCode());
            memberDepositoryDetailDO.setCityName(checkResult.getData().getCityName());
            memberDepositoryDetailDO.setDistrictCode(checkResult.getData().getDistrictCode());
            memberDepositoryDetailDO.setDistrictName(checkResult.getData().getDistrictName());
            memberDepositoryDetailDO.setLabels(checkResult.getData().getLabels());
            //版本
            memberDepositoryDetailDO.setVersion(MemberDetailVersionEnum.TO_BE_VALIDATE.getCode());
            depositoryDetails.add(memberDepositoryDetailDO);
        }

        //强制重启变更流程
        ProcessBO modifyProcess = memberProcessRuleService.findMemberProcessKey(relationDO, MemberProcessTypeEnum.MEMBER_MODIFICATION);
        if(modifyProcess.getEmptyProcess()) {
            relationDO.getDepositDetails().clear();
            memberDepositoryDetailRepository.deleteByRelation(relationDO);
            depositoryDetails.forEach(detail -> detail.setVersion(MemberDetailVersionEnum.USING.getCode()));

        } else {
            if (!StringUtils.hasLength(relationDO.getValidateTask().getProcessKey()) || !relationDO.getValidateTask().getProcessTypeEnum().equals(MemberProcessTypeEnum.MEMBER_MODIFICATION.getCode())) {
                relationDO.getValidateTask().setProcessTypeEnum(MemberProcessTypeEnum.MEMBER_MODIFICATION.getCode());
                relationDO.getValidateTask().setProcessKey(modifyProcess.getProcessKey());
            }

            Wrapper<WorkflowTaskResultBO> taskResult = workflowFeignService.startMemberProcess(relationDO.getValidateTask().getProcessKey(), relationDO.getMemberId(), relationDO.getRoleId(), relationDO.getId());
            if (taskResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
            }

            relationDO.setInnerStatus(taskResult.getData().getInnerStatus());
            relationDO.setOuterStatus(MemberOuterStatusEnum.MODIFYING.getCode());
            relationDO.getValidateTask().setTaskId(taskResult.getData().getTaskId());

            //如果之前有“审核中”的版本，删除
            relationDO.getDepositDetails().removeIf(detail -> detail.getVersion().equals(MemberDetailVersionEnum.TO_BE_VALIDATE.getCode()));
            memberDepositoryDetailRepository.deleteByRelationAndVersion(relationDO, MemberDetailVersionEnum.TO_BE_VALIDATE.getCode());
        }

        memberDepositoryDetailRepository.saveAll(depositoryDetails);
        relationDO.getDepositDetails().addAll(depositoryDetails);

        relationRepository.saveAndFlush(relationDO);

        //外部记录
        baseMemberHistoryService.saveMemberOuterHistory(relationDO, relationDO.getSubRoleName(), MemberValidateHistoryOperationEnum.MODIFY_DEPOSIT_DETAIL, MemberOuterStatusEnum.getCodeMsg(relationDO.getOuterStatus()), "");

        return Wrapper.success();
    }

    /**
     * 变更审核通过后，比较入库资料版本，记录资料变更历史记录
     *
     * @param relationDO 会员关系
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public void saveDepositDetailHistory(MemberRelationDO relationDO) {
        List<MemberDepositoryDetailDO> details = memberDepositoryDetailRepository.findByRelation(relationDO);
        if(CollectionUtils.isEmpty(details)) {
            return;
        }

        List<MemberDepositoryDetailDO> usingList = details.stream().filter(detail -> detail.getVersion().equals(MemberDetailVersionEnum.USING.getCode())).collect(Collectors.toList());

        //只有配置了“变更需要审核”的字段，才需要记录
        List<MemberDepositoryDetailDO> validateList = details.stream().filter(detail -> detail.getVersion().equals(MemberDetailVersionEnum.TO_BE_VALIDATE.getCode()) && NumberUtil.notNullOrZero(detail.getValidate())).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(validateList)) {
            return;
        }

        List<MemberDepositoryDetailHistoryDO> historyList = new ArrayList<>();
        for (MemberDepositoryDetailDO validateDetail : validateList) {
            MemberDepositoryDetailDO usingDetail = usingList.stream().filter(c -> c.getFieldName().equals(validateDetail.getFieldName())).findFirst().orElse(null);
            if (usingDetail == null) {
                continue;
            }

            if(!validateDetail.getDetail().equals(usingDetail.getDetail())) {
                MemberDepositoryDetailHistoryDO historyDO = new MemberDepositoryDetailHistoryDO();
                historyDO.setCreateTime(LocalDateTime.now());
                historyDO.setMemberId(relationDO.getMemberId());
                historyDO.setRoleId(relationDO.getRoleId());
                historyDO.setSubMemberId(relationDO.getSubMemberId());
                historyDO.setSubRoleId(relationDO.getSubRoleId());
                historyDO.setFieldLocalName(validateDetail.getFieldLocalName());
                historyDO.setFieldValue(validateDetail.getDetail());
                historyDO.setLastValue(usingDetail.getDetail());
                historyList.add(historyDO);
            }
        }

        if(!CollectionUtils.isEmpty(historyList)) {
            memberDepositoryDetailHistoryRepository.saveAll(historyList);
        }
    }

    /**
     * 检查入库资料，并保存。调用方要再保存一次MemberRelationDO
     *
     * @param relationDO 会员关系
     * @param detailMap     新增的会员入库资料
     * @return 检查是否通过
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> checkAndSaveMemberDepositoryDetail(MemberRelationDO relationDO, Map<String, Object> detailMap) {
        //如果已经存在“待审核”的入库资料，用作比对；否则用流程规则配置中角色关联的入库资料做比对
        List<MemberDepositoryDetailDO> validatingDetails = memberDepositoryDetailRepository.findByRelationAndVersion(relationDO, MemberDetailVersionEnum.TO_BE_VALIDATE.getCode());
        List<MemberConfigDO> memberConfigList;
        if(CollectionUtils.isEmpty(validatingDetails)) {
            memberConfigList = findMemberDepositoryConfig(relationDO.getMemberId(), relationDO.getRoleId(), relationDO.getSubRole());
        } else {
            memberConfigList = validatingDetails.stream().map(MemberDepositoryDetailDO::getMemberConfig).collect(Collectors.toList());
        }

        //检查并生成“待审核”的入库资料
        Wrapper<List<MemberDepositoryDetailDO>> checkResult = checkMemberDepositoryDetail(relationDO, memberConfigList, detailMap, MemberDetailVersionEnum.TO_BE_VALIDATE);
        if(checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(checkResult.getCode(), checkResult.getMessage());
        }

        List<MemberDepositoryDetailDO> depositoryDetails = checkResult.getData();
        //删除已经存在的“待审核”的入库资料
        if(!CollectionUtils.isEmpty(validatingDetails)) {
            relationDO.getDepositDetails().removeIf(detail -> detail.getVersion().equals(MemberDetailVersionEnum.TO_BE_VALIDATE.getCode()));
            memberDepositoryDetailRepository.deleteAll(validatingDetails);
        }

        memberDepositoryDetailRepository.saveAll(depositoryDetails);
        relationDO.getDepositDetails().addAll(depositoryDetails);

        return Wrapper.success();
    }

    /**
     * 申请成为会员时，检查入库资料，调用方要设置MemberRelationDO并保存
     *
     * @param upperMemberId 上级会员Id
     * @param upperRoleId   上级会员角色Id
     * @param subRole 下级会员角色
     * @param detailMap     入库资料
     * @return 入库资料列表
     */
    @Override
    public Wrapper<List<MemberDepositoryDetailDO>> checkMemberDepositoryDetail(Long upperMemberId, Long upperRoleId, RoleDO subRole, Map<String, Object> detailMap) {
        List<MemberConfigDO> memberConfigList = findMemberDepositoryConfig(upperMemberId, upperRoleId, subRole);

        return checkMemberDepositoryDetail(null, memberConfigList, detailMap, MemberDetailVersionEnum.TO_BE_VALIDATE);
    }

    /**
     * 检查并生成指定版本的入库资料
     *
     * @param relationDO       入库资料关联的会员关系，如果为Null，调用方要设置MemberRelationDO并保存
     * @param memberConfigList 注册资料列表
     * @param detailMap        前端传递的入库资料Map
     * @param versionEnum      指定版本
     * @return 入库资料列表
     */
    @Override
    public Wrapper<List<MemberDepositoryDetailDO>> checkMemberDepositoryDetail(MemberRelationDO relationDO, List<MemberConfigDO> memberConfigList, Map<String, Object> detailMap, MemberDetailVersionEnum versionEnum) {
        if(CollectionUtils.isEmpty(memberConfigList)) {
            return Wrapper.success(new ArrayList<>());
        }

        //判断入库资料字段是否齐全
        Wrapper<Void> checkFieldResult = baseMemberRegisterDetailService.checkDetailFields(memberConfigList, detailMap);
        if(checkFieldResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(checkFieldResult.getCode(), checkFieldResult.getMessage());
        }

        List<MemberDepositoryDetailDO> depositoryDetails = new ArrayList<>();

        for (Map.Entry<String, Object> entry : detailMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue() instanceof HashMap ? SecurityStringUtils.serializeObject(entry.getValue()) : String.valueOf(entry.getValue());

            MemberConfigDO configDO = memberConfigList.stream().filter(c -> c.getFieldName().equals(key)).findFirst().orElse(null);
            if (configDO == null) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DETAIL_FIELD_DOES_NOT_EXIST);
            }

            Wrapper<DetailCheckBO> checkResult = baseMemberRegisterDetailService.checkDetail(configDO, value);
            if(checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(checkResult.getCode(), checkResult.getMessage());
            }

            MemberDepositoryDetailDO memberDepositoryDetailDO = new MemberDepositoryDetailDO();
            memberDepositoryDetailDO.setCreateTime(LocalDateTime.now());
            memberDepositoryDetailDO.setMemberConfig(configDO);
            memberDepositoryDetailDO.setGroupName(configDO.getGroupName());
            memberDepositoryDetailDO.setRelation(relationDO);
            //版本
            memberDepositoryDetailDO.setVersion(versionEnum.getCode());
            memberDepositoryDetailDO.setFieldName(configDO.getFieldName());
            memberDepositoryDetailDO.setFieldLocalName(configDO.getFieldLocalName());
            memberDepositoryDetailDO.setFieldType(configDO.getFieldType());
            memberDepositoryDetailDO.setAttr(configDO.getAttr());
            memberDepositoryDetailDO.setTagEnum(configDO.getTagEnum());
            memberDepositoryDetailDO.setStatus(configDO.getFieldStatus());
            memberDepositoryDetailDO.setValidate(configDO.getValidate());
            memberDepositoryDetailDO.setDetail(checkResult.getData().getDetail());
            memberDepositoryDetailDO.setProvinceCode(checkResult.getData().getProvinceCode());
            memberDepositoryDetailDO.setProvinceName(checkResult.getData().getProvinceName());
            memberDepositoryDetailDO.setCityCode(checkResult.getData().getCityCode());
            memberDepositoryDetailDO.setCityName(checkResult.getData().getCityName());
            memberDepositoryDetailDO.setDistrictCode(checkResult.getData().getDistrictCode());
            memberDepositoryDetailDO.setDistrictName(checkResult.getData().getDistrictName());
            memberDepositoryDetailDO.setLabels(checkResult.getData().getLabels());
            depositoryDetails.add(memberDepositoryDetailDO);
        }

        return Wrapper.success(depositoryDetails);
    }

    /**
     * 查询会员入库资料
     *
     * @param relationDO  会员关系
     * @param versionEnum 版本
     * @return 查询结果
     */
    @Override
    public List<RegisterDetailGroupVO> findMemberDepositoryDetail(MemberRelationDO relationDO, MemberDetailVersionEnum versionEnum) {
        List<MemberDepositoryDetailDO> depositDetails = memberDepositoryDetailRepository.findByRelationAndVersion(relationDO, versionEnum.getCode());
        if (CollectionUtils.isEmpty(depositDetails)) {
            return new ArrayList<>();
        }

        //筛选出状态为 “启用” 的配置，按照groupName进行分组
        Map<String, List<MemberDepositoryDetailDO>> groupList = depositDetails.stream().filter(c -> c.getStatus().equals(MemberConfigStatusEnum.ENABLED.getCode()))
                .collect(Collectors.groupingBy(MemberDepositoryDetailDO::getGroupName));

        return groupList.entrySet().stream().map(e -> {
            RegisterDetailGroupVO detailGroup = new RegisterDetailGroupVO();
            detailGroup.setGroupName(e.getKey());

            List<RegisterDetailVO> elements = e.getValue().stream().map(c -> {
                RegisterDetailVO detail = new RegisterDetailVO();
                detail.setFieldName(c.getFieldName());
                detail.setFieldLocalName(c.getFieldLocalName());
                detail.setFieldType(c.getFieldType());
                detail.setAttr(c.getAttr());
                detail.setFieldEmpty(c.getMemberConfig().getFieldEmpty());
                detail.setFieldLength(c.getMemberConfig().getFieldLength());
                detail.setFieldOrder(c.getMemberConfig().getFieldOrder());
                detail.setFieldRemark(c.getMemberConfig().getFieldRemark());
                detail.setRuleEnum(c.getMemberConfig().getRuleEnum());
                detail.setPattern(c.getMemberConfig().getRuleEnum().equals(0) ? "" : MemberConfigCheckRuleEnum.getJsPattern(c.getMemberConfig().getRuleEnum()));
                detail.setMsg(c.getMemberConfig().getRuleEnum().equals(0) ? "" : MemberConfigCheckRuleEnum.getMsg(c.getMemberConfig().getRuleEnum()));
                detail.setFieldEnum(CollectionUtils.isEmpty(c.getMemberConfig().getLabels()) ? new ArrayList<>() : c.getMemberConfig().getLabels().stream().sorted(Comparator.comparingInt(MemberConfigLabelDO::getLabelOrder)).map(label -> new ConfigDetailLabelVO(label.getId(), label.getLabelValue())).collect(Collectors.toList()));

                DetailValueBO valueBO = getDetailValue(c);
                detail.setFieldValue(valueBO.getFieldValue());
                detail.setLastValue(valueBO.getLastValue());

                return detail;
            }).sorted(Comparator.comparingInt(RegisterDetailVO::getFieldOrder)).collect(Collectors.toList());

            detailGroup.setElements(elements);
            return detailGroup;
        }).sorted(Comparator.comparingInt(a -> a.getElements().get(0).getFieldOrder())).collect(Collectors.toList());
    }

    /**
     * 查询会员入库资料（先查询“正在使用”的版本，如无则查询“正在审核”的版本）
     *
     * @param relationDO 会员关系
     * @return 查询结果
     */
    @Override
    public List<RegisterDetailGroupVO> switchMemberDepositoryDetail(MemberRelationDO relationDO) {
        List<MemberDepositoryDetailDO> depositDetailList = memberDepositoryDetailRepository.findByRelation(relationDO);
        if (CollectionUtils.isEmpty(depositDetailList)) {
            return new ArrayList<>();
        }

        List<MemberDepositoryDetailDO> depositDetails = depositDetailList.stream().filter(detail -> detail.getVersion().equals(MemberDetailVersionEnum.USING.getCode())).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(depositDetails)) {
            depositDetails = depositDetailList.stream().filter(detail -> detail.getVersion().equals(MemberDetailVersionEnum.TO_BE_VALIDATE.getCode())).collect(Collectors.toList());
        }

        //筛选出状态为 “启用” 的配置，按照groupName进行分组
        Map<String, List<MemberDepositoryDetailDO>> groupList = depositDetails.stream().filter(c -> c.getStatus().equals(MemberConfigStatusEnum.ENABLED.getCode()))
                .collect(Collectors.groupingBy(MemberDepositoryDetailDO::getGroupName));

        return groupList.entrySet().stream().map(e -> {
            RegisterDetailGroupVO detailGroup = new RegisterDetailGroupVO();
            detailGroup.setGroupName(e.getKey());

            List<RegisterDetailVO> elements = e.getValue().stream().map(c -> {
                RegisterDetailVO detail = new RegisterDetailVO();
                detail.setFieldName(c.getFieldName());
                detail.setFieldLocalName(c.getFieldLocalName());
                detail.setFieldType(c.getFieldType());
                detail.setAttr(c.getAttr());
                detail.setFieldEmpty(c.getMemberConfig().getFieldEmpty());
                detail.setFieldLength(c.getMemberConfig().getFieldLength());
                detail.setFieldOrder(c.getMemberConfig().getFieldOrder());
                detail.setFieldRemark(c.getMemberConfig().getFieldRemark());
                detail.setRuleEnum(c.getMemberConfig().getRuleEnum());
                detail.setPattern(c.getMemberConfig().getRuleEnum().equals(0) ? "" : MemberConfigCheckRuleEnum.getJsPattern(c.getMemberConfig().getRuleEnum()));
                detail.setMsg(c.getMemberConfig().getRuleEnum().equals(0) ? "" : MemberConfigCheckRuleEnum.getMsg(c.getMemberConfig().getRuleEnum()));
                detail.setFieldEnum(CollectionUtils.isEmpty(c.getMemberConfig().getLabels()) ? new ArrayList<>() : c.getMemberConfig().getLabels().stream().sorted(Comparator.comparingInt(MemberConfigLabelDO::getLabelOrder)).map(label -> new ConfigDetailLabelVO(label.getId(), label.getLabelValue())).collect(Collectors.toList()));

                DetailValueBO valueBO = getDetailValue(c);
                detail.setFieldValue(valueBO.getFieldValue());
                detail.setLastValue(valueBO.getLastValue());

                return detail;
            }).sorted(Comparator.comparingInt(RegisterDetailVO::getFieldOrder)).collect(Collectors.toList());

            detailGroup.setElements(elements);
            return detailGroup;
        }).sorted(Comparator.comparingInt(a -> a.getElements().get(0).getFieldOrder())).collect(Collectors.toList());
    }

    /**
     * 查询会员入库资料（合并版本）
     *
     * @param relationDO 会员关系
     * @return 查询结果
     */
    @Override
    public List<DetailTextGroupVO> mergeMemberDepositoryDetailText(MemberRelationDO relationDO) {
        List<MemberDepositoryDetailDO> depositoryDetails = memberDepositoryDetailRepository.findByRelation(relationDO);
        if(CollectionUtils.isEmpty(depositoryDetails)) {
            return new ArrayList<>();
        }

        List<MemberDepositoryDetailDO> usingList = depositoryDetails.stream().filter(depositoryDetail -> depositoryDetail.getVersion().equals(MemberDetailVersionEnum.USING.getCode())).collect(Collectors.toList());
        List<MemberDepositoryDetailDO> modifiedList = depositoryDetails.stream().filter(depositoryDetail -> depositoryDetail.getVersion().equals(MemberDetailVersionEnum.TO_BE_VALIDATE.getCode())).collect(Collectors.toList());

        if(CollectionUtils.isEmpty(modifiedList)) {
            //按照groupName进行分组
            Map<String, List<MemberDepositoryDetailDO>> groupList = usingList.stream().collect(Collectors.groupingBy(MemberDepositoryDetailDO::getGroupName));

            return groupList.entrySet().stream().map(e -> {
                DetailTextGroupVO detailGroup = new DetailTextGroupVO();
                detailGroup.setGroupName(e.getKey());
                List<DetailTextVO> elements = e.getValue().stream().map(c -> {
                    DetailTextVO detail = new DetailTextVO();
                    detail.setFieldType(c.getFieldType());
                    detail.setFieldLocalName(c.getFieldLocalName());
                    detail.setFieldOrder(c.getMemberConfig().getFieldOrder());
                    detail.setFieldValue(c.getDetail());
                    detail.setLastValue("");
                    return detail;
                }).sorted(Comparator.comparingInt(DetailTextVO::getFieldOrder)).collect(Collectors.toList());

                detailGroup.setElements(elements);
                return detailGroup;
            }).sorted(Comparator.comparingInt(a -> a.getElements().get(0).getFieldOrder())).collect(Collectors.toList());
        } else {
            //按照groupName进行分组
            Map<String, List<MemberDepositoryDetailDO>> groupList = modifiedList.stream().collect(Collectors.groupingBy(MemberDepositoryDetailDO::getGroupName));

            return groupList.entrySet().stream().map(e -> {
                DetailTextGroupVO detailGroup = new DetailTextGroupVO();
                detailGroup.setGroupName(e.getKey());
                List<DetailTextVO> elements = e.getValue().stream().map(c -> {
                    MemberDepositoryDetailDO usingDetail = usingList.stream().filter(d -> d.getFieldName().equals(c.getFieldName())).findFirst().orElse(null);
                    DetailTextVO detail = new DetailTextVO();
                    detail.setFieldType(c.getFieldType());
                    detail.setFieldLocalName(c.getFieldLocalName());
                    detail.setFieldOrder(c.getMemberConfig().getFieldOrder());
                    detail.setFieldValue(c.getDetail());
                    detail.setLastValue(usingDetail == null ? "" : usingDetail.getDetail());
                    return detail;
                }).sorted(Comparator.comparingInt(DetailTextVO::getFieldOrder)).collect(Collectors.toList());

                detailGroup.setElements(elements);
                return detailGroup;
            }).sorted(Comparator.comparingInt(a -> a.getElements().get(0).getFieldOrder())).collect(Collectors.toList());
        }
    }

    /**
     * 查询会员入库资料（指定版本）
     *
     * @param relationDO  会员关系
     * @param versionEnum 版本
     * @return 查询结果
     */
    @Override
    public List<DetailTextGroupVO> findMemberDepositoryDetailText(MemberRelationDO relationDO, MemberDetailVersionEnum versionEnum) {
        List<MemberDepositoryDetailDO> depositoryDetails = memberDepositoryDetailRepository.findByRelationAndVersion(relationDO, versionEnum.getCode());
        if(CollectionUtils.isEmpty(depositoryDetails)) {
            return new ArrayList<>();
        }

        //按照groupName进行分组
        Map<String, List<MemberDepositoryDetailDO>> groupList = depositoryDetails.stream().collect(Collectors.groupingBy(MemberDepositoryDetailDO::getGroupName));

        return groupList.entrySet().stream().map(e -> {
            DetailTextGroupVO detailGroup = new DetailTextGroupVO();
            detailGroup.setGroupName(e.getKey());
            List<DetailTextVO> elements = e.getValue().stream().map(c -> {
                DetailTextVO detail = new DetailTextVO();
                detail.setFieldType(c.getFieldType());
                detail.setFieldLocalName(c.getFieldLocalName());
                detail.setFieldOrder(c.getMemberConfig().getFieldOrder());
                detail.setFieldValue(c.getDetail());
                detail.setLastValue("");
                return detail;
            }).sorted(Comparator.comparingInt(DetailTextVO::getFieldOrder)).collect(Collectors.toList());

            detailGroup.setElements(elements);
            return detailGroup;
        }).sorted(Comparator.comparingInt(a -> a.getElements().get(0).getFieldOrder())).collect(Collectors.toList());
    }

    /**
     * 查询会员入库资料（先查找审核通过的版本，如果没有则查找正在审核的版本）
     *
     * @param relationDO  会员关系
     * @return 查询结果
     */
    @Override
    public List<DetailTextGroupVO> switchMemberDepositoryDetailText(MemberRelationDO relationDO) {
        List<MemberDepositoryDetailDO> depositoryDetailList = memberDepositoryDetailRepository.findByRelation(relationDO);
        if(CollectionUtils.isEmpty(depositoryDetailList)) {
            return new ArrayList<>();
        }

        List<MemberDepositoryDetailDO> depositoryDetails = depositoryDetailList.stream().filter(detail -> detail.getVersion().equals(MemberDetailVersionEnum.USING.getCode())).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(depositoryDetails)) {
            depositoryDetails = depositoryDetailList.stream().filter(detail -> detail.getVersion().equals(MemberDetailVersionEnum.TO_BE_VALIDATE.getCode())).collect(Collectors.toList());
        }

        if(CollectionUtils.isEmpty(depositoryDetails)) {
            return new ArrayList<>();
        }

        //按照groupName进行分组
        Map<String, List<MemberDepositoryDetailDO>> groupList = depositoryDetails.stream().collect(Collectors.groupingBy(MemberDepositoryDetailDO::getGroupName));

        return groupList.entrySet().stream().map(e -> {
            DetailTextGroupVO detailGroup = new DetailTextGroupVO();
            detailGroup.setGroupName(e.getKey());
            List<DetailTextVO> elements = e.getValue().stream().map(c -> {
                DetailTextVO detail = new DetailTextVO();
                detail.setFieldType(c.getFieldType());
                detail.setFieldLocalName(c.getFieldLocalName());
                detail.setFieldOrder(c.getMemberConfig().getFieldOrder());
                detail.setFieldValue(c.getDetail());
                detail.setLastValue("");
                return detail;
            }).sorted(Comparator.comparingInt(DetailTextVO::getFieldOrder)).collect(Collectors.toList());

            detailGroup.setElements(elements);
            return detailGroup;
        }).sorted(Comparator.comparingInt(a -> a.getElements().get(0).getFieldOrder())).collect(Collectors.toList());
    }

    /**
     * 入库审核通过后，修改入库资料版本为“Using”
     *
     * @param relationDO 会员关系
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public void updateDepositDetailToUsing(MemberRelationDO relationDO) {
        List<MemberDepositoryDetailDO> details = memberDepositoryDetailRepository.findByRelation(relationDO);

        List<MemberDepositoryDetailDO> updateList = details.stream().filter(detail -> detail.getVersion().equals(MemberDetailVersionEnum.TO_BE_VALIDATE.getCode())).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(updateList)) {
            return;
        }

        List<MemberDepositoryDetailDO> deleteList = details.stream().filter(detail -> detail.getVersion().equals(MemberDetailVersionEnum.USING.getCode())).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(deleteList)) {
            memberDepositoryDetailRepository.deleteAll(deleteList);
        }

        updateList.forEach(detail -> detail.setVersion(MemberDetailVersionEnum.USING.getCode()));
        memberDepositoryDetailRepository.saveAll(updateList);
    }

    /**
     * 检查注册资料、入库资料的字段是否齐全
     *
     * @param depositoryDetailList 入库资料列表
     * @param detailMap            前端传递的入库资料
     * @return 检查结果
     */
    @Override
    public Wrapper<Void> checkDetailFields(List<MemberDepositoryDetailDO> depositoryDetailList, Map<String, Object> detailMap) {
        if(CollectionUtils.isEmpty(depositoryDetailList)) {
            return Wrapper.success();
        }

        if(CollectionUtils.isEmpty(detailMap)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DEPOSITORY_DETAIL_IS_MISSING);
        }

        MemberDepositoryDetailDO depositoryDetail = depositoryDetailList.stream().filter(detail -> detailMap.keySet().stream().noneMatch(key -> key.equals(detail.getFieldName()))).findFirst().orElse(null);
        if(depositoryDetail != null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DEPOSITORY_DETAIL_IS_MISSING, MemberStringEnum.FILL_IN.getName() + depositoryDetail.getFieldLocalName());
        }

        return Wrapper.success();
    }

    /**
     * 查询入库资料时，根据入库资料的FieldType，获取前端显示的值
     *
     * @param detailDO 入库资料
     * @return 字段值
     */
    private DetailValueBO getDetailValue(MemberDepositoryDetailDO detailDO) {
        DetailValueBO detail = new DetailValueBO();
        //省、市、区下拉框
        if ("area".equals(detailDO.getFieldType())) {
            detail.setFieldValue(new RegisterAreaVO(detailDO.getProvinceCode(), detailDO.getCityCode(), detailDO.getDistrictCode()));
            detail.setLastValue(new RegisterAreaVO());
        } else if ("select".equals(detailDO.getFieldType()) || "radio".equals(detailDO.getFieldType())) {
            MemberDetailLabelBO labelBO = detailDO.getLabels().stream().findFirst().orElse(null);
            detail.setFieldValue(labelBO == null ? null : labelBO.getLabelId());
            detail.setLastValue(null);
        } else if ("checkbox".equals(detailDO.getFieldType())) {
            detail.setFieldValue(detailDO.getLabels().stream().map(MemberDetailLabelBO::getLabelId).collect(Collectors.toList()));
            detail.setLastValue(new ArrayList<>());
        } else {
            detail.setFieldValue(detailDO.getDetail());
            detail.setLastValue("");
        }

        return detail;
    }

    /**
     * 查询入库资料时，根据入库资料的FieldType，获取前端显示的值
     *
     * @param detailDO 入库资料
     * @return 字段值
     */
    private DetailValueBO getDetailValue(MemberConfigDO detailDO) {
        DetailValueBO detail = new DetailValueBO();
        //省、市、区下拉框
        if ("area".equals(detailDO.getFieldType())) {
            detail.setFieldValue(new RegisterAreaVO());
            detail.setLastValue(new RegisterAreaVO());
        } else if ("select".equals(detailDO.getFieldType()) || "radio".equals(detailDO.getFieldType())) {
            detail.setFieldValue(null);
            detail.setLastValue(null);
        } else if ("checkbox".equals(detailDO.getFieldType())) {
            detail.setFieldValue(new ArrayList<>());
            detail.setLastValue(new ArrayList<>());
        } else {
            detail.setFieldValue("");
            detail.setLastValue("");
        }

        return detail;
    }
}
